<?php


namespace Drupal\wx_transfers;


use Drupal\wx_pay\WxPayMiniPayController;
use Drupal\wx_transfers\Entity\WxTransfers;
use ServicesException;

class WxTransfersController extends WxPayMiniPayController {

  /**
   * @param string $openid
   * @param int $amount
   * @param string $desc
   * @param int $check 校验真实姓名 0 否 1 是
   * @param string $realname 实名
   *
   * @return \Drupal\wx_transfers\Entity\WxTransfers
   * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
   * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
   * @throws \GuzzleHttp\Exception\GuzzleException
   * @throws \ServicesException
   */
  function toBalance(string $module, string $attach, string $openid, int $amount, string $desc, int $check = 0, string $realname = '') {
    /**
     * NO_CHECK：不校验真实姓名
     * FORCE_CHECK：强校验真实姓名
     */
    $check_name = 'NO_CHECK';
    if ($check == 1) {
      $check_name = 'FORCE_CHECK';
      if (empty($realname)) {
        throw new ServicesException('校验真实姓名,请填写姓名');
      }
    }
    $partner_trade_no = $this->makePartnerTradeNo();
    $result = $this->payment->transfer->toBalance([
      'partner_trade_no' => $partner_trade_no,
      'openid' => $openid,
      'check_name' => $check_name,
      're_user_name' => $realname,
      'amount' => variable_get_value('wx_pay_pay_debug') ? 1 : $amount,
      'desc' => $desc,
    ]);

    $wxTransfers = new WxTransfers();
    $wxTransfers->module = $module;
    $wxTransfers->attach = $attach;
    $wxTransfers->appid = $this->getAppId();
    $wxTransfers->mch_id = $this->getMchId();
    $wxTransfers->openid = $openid;
    $wxTransfers->partner_trade_no = $partner_trade_no;
    $wxTransfers->check_name = $check;
    $wxTransfers->re_user_name = $realname;
    $wxTransfers->amount = $amount;
    $wxTransfers->note = $desc;
    if ($result['return_code'] == 'SUCCESS') {
      if (isset($result['err_code'])) {
        $wxTransfers->err_code = $result['err_code'];
      }
      //https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_3
      switch ($wxTransfers->err_code) {
        case 'NO_AUTH':
        case 'AMOUNT_LIMIT':
        case 'PARAM_ERROR':
        case 'OPENID_ERROR':
        case 'SEND_FAILED':
        case 'XML_ERROR':
        case 'FATAL_ERROR':
        case 'RECV_ACCOUNT_NOT_ALLOWED':
        case 'PAY_CHANNEL_NOT_ALLOWED':
          $wxTransfers->status = 2;
          break;
        default:
        case 'NOTENOUGH':
        case 'SYSTEMERROR':
        case 'NAME_MISMATCH':
        case 'SIGN_ERROR':
        case 'FREQ_LIMIT':
        case 'MONEY_LIMIT':
        case 'CA_ERROR':
        case 'V2_ACCOUNT_SIMPLE_BAN':
        case 'PARAM_IS_NOT_UTF8':
        case 'SENDNUM_LIMIT':
          //这些情况可以重试
          $wxTransfers->status = 1;
          $wxTransfers->next_retry = REQUEST_TIME + ((5 - $wxTransfers->retry) * 300);
          $wxTransfers->retry--;
          break;
      }
      if (isset($result['err_code_des'])) {
        $wxTransfers->err_code_des = $result['err_code_des'];
      }
      if ($result['result_code'] == 'SUCCESS') {
        $wxTransfers->payment_no = $result['payment_no'];
        $wxTransfers->payment_time = $result['payment_time'];
        $wxTransfers->status = 3;
      }
    }
    $wxTransfers->save();
    $this->invoke($wxTransfers);
    return $wxTransfers;
  }

  protected function makePartnerTradeNo() {
    return 'CX' . $this->makeOutTradeNo();
  }

  protected function invoke(WxTransfers $wxTransfers) {
    //状态 0 处理中 1 失败(可以重试) 2 失败(不可重试) 3 成功
    switch ($wxTransfers->status) {
      case 0:
        break;
      case 1:
        break;
      case 2:
      case 3:
        module_invoke($wxTransfers->module, 'wx_transfers_notify', $wxTransfers);
        break;
    }
  }

  /**
   * @param \Drupal\wx_transfers\Entity\WxTransfers $wxTransfers
   *
   * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
   * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
   * @throws \GuzzleHttp\Exception\GuzzleException
   */
  function retry(WxTransfers $wxTransfers) {
    $check_name = 'NO_CHECK';
    if ($wxTransfers->check_name == 1) {
      $check_name = 'FORCE_CHECK';
    }
    $partner_trade_no = $wxTransfers->partner_trade_no;
    $result = $this->payment->transfer->toBalance([
      'partner_trade_no' => $partner_trade_no,
      'openid' => $wxTransfers->openid,
      'check_name' => $check_name,
      're_user_name' => $wxTransfers->re_user_name,
      'amount' => variable_get_value('wx_pay_pay_debug') ? 1 : $wxTransfers->amount,
      'desc' => $wxTransfers->note,
    ]);
    $wxTransfers->appid = $this->getAppId();
    $wxTransfers->mch_id = $this->getMchId();
    $wxTransfers->partner_trade_no = $partner_trade_no;
    if ($result['return_code'] == 'SUCCESS') {
      $wxTransfers->err_code = $result['err_code'];
      switch ($wxTransfers->err_code) {
        case 'NO_AUTH':
        case 'AMOUNT_LIMIT':
        case 'PARAM_ERROR':
        case 'OPENID_ERROR':
        case 'SEND_FAILED':
        case 'XML_ERROR':
        case 'FATAL_ERROR':
        case 'RECV_ACCOUNT_NOT_ALLOWED':
        case 'PAY_CHANNEL_NOT_ALLOWED':
          $wxTransfers->status = 2;
          break;
        default:
        case 'NOTENOUGH':
        case 'SYSTEMERROR':
        case 'NAME_MISMATCH':
        case 'SIGN_ERROR':
        case 'FREQ_LIMIT':
        case 'MONEY_LIMIT':
        case 'CA_ERROR':
        case 'V2_ACCOUNT_SIMPLE_BAN':
        case 'PARAM_IS_NOT_UTF8':
        case 'SENDNUM_LIMIT':
          //这些情况可以重试
          $wxTransfers->status = 1;
          $wxTransfers->next_retry = REQUEST_TIME + ((5 - $wxTransfers->retry) * 300);
          $wxTransfers->retry--;
          break;
      }
      $wxTransfers->err_code_des = $result['err_code_des'];
      if ($result['result_code'] == 'SUCCESS') {
        $wxTransfers->payment_no = $result['payment_no'];
        $wxTransfers->payment_time = $result['payment_time'];
        $wxTransfers->status = 3;
      }
    }
    $wxTransfers->save();
    $this->invoke($wxTransfers);
  }

  protected function getIndexNumber() {
    $old_index = variable_get('wx_transfers_index_number', 0);
    if ($old_index > 98) {
      $new_index = 0;
    }
    else {
      $new_index = $old_index + 1;
    }
    variable_set('wx_transfers_index_number', $new_index);
    return $old_index;
  }
}
